package net.chrisrichardson.ec2deployer.cluster

import net.chrisrichardson.ec2deployer.core.AWSProperties
import groovy.mock.interceptor.MockFor
import net.chrisrichardson.ec2deployer.core.*
import net.chrisrichardson.ec2deployer.applications.*

class JmeterTierTest extends GroovyTestCase {

    AWSProperties awsProperties
    def mockAppServerTier
    def mockApacheServer
    def apacheInstance
    def mockEc2Server
    def mockEc2
    ClusterSpec clusterSpec
    def mockWebServerTier
    def mockDatabaseTier
    def someInstance
    def mockJmeterLogAnalyzer
    def mockJmeterApplication
    def mockSarMonitor
    def jmeterInstance
    def mockTerracottaTier

    public void setUp() {
        def props = new Properties()
        awsProperties = new AWSProperties(props)
        mockAppServerTier = new MockFor(AppServerTier.class)
        mockWebServerTier = new MockFor(WebServerTier)
        mockDatabaseTier = new MockFor(DatabaseTier)
        mockTerracottaTier = new MockFor(TerracottaTier)

        mockJmeterLogAnalyzer = new MockFor(JmeterLogAnalyzer)
        mockJmeterApplication = new MockFor(JmeterApplication)
        mockSarMonitor = new MockFor(SarMonitor)

        mockApacheServer = new MockFor(ApacheServer.class)
        mockEc2Server = new MockFor(EC2Server)
        mockEc2 = new MockFor(EC2.class)
        clusterSpec = new ClusterSpec().tomcats(1).slaves(1).webApp('target/ptrack', "ptrack").catalinaOptsBuilder({builder, databasePrivateDnsName ->}).schema("ptrack", ["ptrack": "ptrack"])
    }

    public void testAssignHosts() {
        def ec2 = new EC2(awsProperties)

        mockAppServerTier.use {
            mockWebServerTier.use {
                mockEc2Server.use {
                    mockTerracottaTier.use {
                    def appServerTier = new AppServerTier()
                    def webServerTier = new WebServerTier()
                    def databaseTier = new DatabaseTier()
                    def jmeterInstance = new EC2Server()
                    def terracottaTier = new TerracottaTier()

                    def jmeterTier = new JmeterTier(ec2, clusterSpec, appServerTier, webServerTier, databaseTier, terracottaTier)

                    def hosts = new ClusterHosts(jmeter: jmeterInstance)

                    jmeterTier.assignHosts(hosts)

                    assertSame jmeterInstance, jmeterTier.jmeter.host
                }
                }

            }
        }
    }

    public void testAssignHostsWithNoHost() {
        def ec2 = new EC2(awsProperties)

        mockAppServerTier.use {
            mockWebServerTier.use {
                mockEc2Server.use {
                    mockTerracottaTier.use {
                    def appServerTier = new AppServerTier()
                    def webServerTier = new WebServerTier()
                    def databaseTier = new DatabaseTier()
                    def jmeterInstance = new EC2Server()
                    def terracottaTier = new TerracottaTier()

                    def hosts = new ClusterHosts()

                    def jmeterTier = new JmeterTier(ec2, clusterSpec, appServerTier, webServerTier, databaseTier, terracottaTier)

                    jmeterTier.assignHosts(hosts)

                    assertNull jmeterTier.jmeter

                    assertEquals([], jmeterTier.servers)

                    def stateToSave = [:]
                    jmeterTier.saveState(stateToSave)
                    assert stateToSave.isEmpty()
                }
                }

            }
        }
    }

    public void testLoadTest() {
        def ec2 = new EC2(awsProperties)

        2.times {mockAppServerTier.demand.getNumberOfTomcats {1}}

        mockAppServerTier.demand.getSarMonitors {[new SarMonitor()]}
        mockTerracottaTier.demand.getSarMonitors {[new SarMonitor()]}
        mockWebServerTier.demand.getSarMonitor {new SarMonitor()}
        mockDatabaseTier.demand.getSarMonitor {new SarMonitor()}
        mockDatabaseTier.demand.getSarMonitorsForSlaves { [] }
        mockJmeterApplication.demand.getSarMonitor {new SarMonitor()}

        5.times {mockSarMonitor.demand.start {}}

        mockJmeterApplication.demand.runOnce {a, b, c, d ->}

        mockJmeterLogAnalyzer.demand.analyze {}

        mockAppServerTier.demand.getSarMonitors {[new SarMonitor()]}
        mockTerracottaTier.demand.getSarMonitors {[new SarMonitor()]}
        mockWebServerTier.demand.getSarMonitor {new SarMonitor()}
        mockDatabaseTier.demand.getSarMonitor {new SarMonitor()}
        mockDatabaseTier.demand.getSarMonitorsForSlaves { [] }
        mockJmeterApplication.demand.getSarMonitor {new SarMonitor()}

        5.times {mockSarMonitor.demand.stop {}}

        mockAppServerTier.demand.getSarMonitors {[new SarMonitor()]}
        mockTerracottaTier.demand.getSarMonitors {[new SarMonitor()]}
        mockWebServerTier.demand.getSarMonitor {new SarMonitor()}
        mockDatabaseTier.demand.getSarMonitor {new SarMonitor()}
        mockDatabaseTier.demand.getSarMonitorsForSlaves { [] }
        mockJmeterApplication.demand.getSarMonitor {new SarMonitor()}

        mockJmeterLogAnalyzer.demand.report {a, b, c, d ->}

        mockSarMonitor.use {
            mockAppServerTier.use {
                mockWebServerTier.use {
                    mockEc2Server.use {
                        mockDatabaseTier.use {
                            mockTerracottaTier.use {
                            mockJmeterLogAnalyzer.use {
                                mockJmeterApplication.use {
                                    def appServerTier = new AppServerTier()
                                    def webServerTier = new WebServerTier()
                                    someInstance = new EC2Server()
                                    def jmeterInstance = someInstance
                                    def databaseTier = new DatabaseTier()
                                    def terracottaTier = new TerracottaTier()

                                    def hosts = new ClusterHosts(jmeter: jmeterInstance)

                                    def jmeterTier = new JmeterTier(ec2, clusterSpec, appServerTier, webServerTier, databaseTier, terracottaTier)

                                    jmeterTier.assignHosts(hosts)

                                    def jmxFileName = "foo.jmx"
                                    def threadCounts = [1]

                                    jmeterTier.loadTest(jmxFileName, threadCounts, [])
                                }
                            }
                        }
                        }

                    }

                }
            }
        }
    }

    public void testSaveState() {
        def ec2 = new EC2(awsProperties)

        mockEc2Server.demand.getInstanceId {"i-jmeter"}

        mockAppServerTier.use {
            mockWebServerTier.use {
                mockEc2Server.use {
                    mockTerracottaTier.use {
                    def appServerTier = new AppServerTier()
                    def webServerTier = new WebServerTier()
                    def databaseTier = new DatabaseTier()
                    def jmeterInstance = new EC2Server()
                    def terracottaTier = new TerracottaTier()

                    def hosts = new ClusterHosts(jmeter: jmeterInstance)

                    def jmeterTier = new JmeterTier(ec2, clusterSpec, appServerTier, webServerTier, databaseTier, terracottaTier)

                    jmeterTier.assignHosts(hosts)

                    def state = [:]
                    jmeterTier.saveState(state)

                    assertEquals(["jmeter": ["i-jmeter"]], state)

                }
                }

            }
        }
    }

    public void testRestoreState() {

        mockEc2.demand.findInstance{ id -> jmeterInstance }

        mockEc2.use {
            def ec2 = new EC2(awsProperties)
            mockAppServerTier.use {
                mockWebServerTier.use {
                    mockEc2Server.use {
                        mockTerracottaTier.use {
                        def appServerTier = new AppServerTier()
                        def webServerTier = new WebServerTier()
                        def databaseTier = new DatabaseTier()
                        def terracottaTier = new TerracottaTier()

                        jmeterInstance = new EC2Server()

                        def hosts = new ClusterHosts(jmeter: jmeterInstance)

                        def jmeterTier = new JmeterTier(ec2, clusterSpec, appServerTier, webServerTier, databaseTier, terracottaTier)

                        def state = ["jmeter": ["i-jmeter"]]
                        jmeterTier.restoreState(state)
                        }
                    }

                }
            }
        }

    }

    public void testRestoreStateNoJmeter() {

        mockEc2.use {
            def ec2 = new EC2(awsProperties)
            mockAppServerTier.use {
                mockWebServerTier.use {
                    mockEc2Server.use {
                        mockTerracottaTier.use {
                        def appServerTier = new AppServerTier()
                        def webServerTier = new WebServerTier()
                        def databaseTier = new DatabaseTier()
                        def terracottaTier = new TerracottaTier()

                        jmeterInstance = new EC2Server()

                        def hosts = new ClusterHosts(jmeter: jmeterInstance)

                        def jmeterTier = new JmeterTier(ec2, clusterSpec, appServerTier, webServerTier, databaseTier, terracottaTier)

                        def state = [:]
                        jmeterTier.restoreState(state)
                        assertNull jmeterTier.jmeter
                        }
                    }

                }
            }
        }

    }

}